#include <linux/module.h>
#include <linux/pci.h>
#include "drv_dim.h"
#include "drv_pcie.h"
#include "drv_cdev.h"
#include "drv_di.h"
#include "drv_xcan.h"

#if (HARD_VER == 0)
#define DIM_DI_DEV_NUM          16                  /* DI 设备数量 */
#define DIM_CANFD_DEV_NUM       1                   /* CANFD 设备数量 */
#elif (HARD_VER == 1)
#define DIM_DI_DEV_NUM          24                  /* DI 设备数量 */
#define DIM_CANFD_DEV_NUM       2                   /* CANFD 设备数量 */
#endif
#define DIM_DI_DRV_NAME         "pcie_di"           /* DI 设备名称 */
#define DIM_CANFD_DRV_NAME      "pcie_canfd"        /* CANFD 设备名称 */

struct cdev_dev_t dim_di_cdev[DIM_DI_DEV_NUM];          /* DI 模块 DI 字符设备 */
struct di_dev_t dim_di_dev[DIM_DI_DEV_NUM];             /* DI 模块 DI 设备 */
struct cdev_dev_t dim_canfd_cdev[DIM_CANFD_DEV_NUM];    /* ECU 模块 CANFD 字符设备 */
struct xcan_dev_t dim_canfd_dev[DIM_CANFD_DEV_NUM];     /* ECU 模块 CANFD 设备 */

/* PCIe DI 模块 */
struct pcie_dim_t {
    struct device *dev;                 /* Linux 设备指针 */
    struct pcie_dev_t pcie_dev;         /* PCIe 设备 */
    struct di_ctrl_t di_ctrl;           /* DI 控制器 */
    struct xcan_ctrl_t xcanfd_ctrl;     /* CANFD 控制器 */
};

static int pcie_dim_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
    int ret = 0;
    struct pcie_dim_t *pmcdev = NULL;

    dev_info(&pdev->dev, "Probing %04x:%04x", pdev->vendor, pdev->device);
    /* 检查设备是否已被占用 */
    if (pci_get_drvdata(pdev)) {
        dev_warn(&pdev->dev, "device already claimed");
        return -EBUSY;
    }

    /* 分配设备结构内存 */
    pmcdev = devm_kzalloc(&pdev->dev, sizeof(*pmcdev), GFP_KERNEL);
    if (!pmcdev)
        return -ENOMEM;

    pmcdev->dev = &pdev->dev;
    pci_set_drvdata(pdev, pmcdev);

    /* 初始化 PCIe 设备 */
    ret = init_pcie_dev(pdev, &pmcdev->pcie_dev);
    if (ret) {
        dev_err(pmcdev->dev, "Init PCIe device failed");
        goto err_cleanup;
    }

    /* 初始化 DI 控制器 */
    ret = init_di_ctrl(&pmcdev->pcie_dev, dim_di_cdev, &pmcdev->di_ctrl, 
                       dim_di_dev, DIM_DI_DRV_NAME, DIM_DI_DEV_NUM);
    if (ret < 0) {
        dev_err(pmcdev->dev, "Init DI controller failed");
        goto err_cleanup;
    }
    dev_info(pmcdev->dev, "Init DI controller success");

    /* 初始化 CAN FD 控制器 */
    ret = init_xcan_ctrl(&pmcdev->pcie_dev, dim_canfd_cdev, &pmcdev->xcanfd_ctrl, 
                         dim_canfd_dev, DIM_CANFD_DRV_NAME, DIM_CANFD_DEV_NUM, &xcan_canfd2_data);
    if (ret < 0) {
        dev_err(pmcdev->dev, "Init CANFD device failed");
        goto err_cleanup_di;
    }
    dev_info(pmcdev->dev, "Init CANFD device success");

    dev_info(&pdev->dev, "Probe PCIe %s device success", DIM_DRV_NAME);

    return 0;

err_cleanup_di:
    /* 注销 DI 控制器 */
    exit_di_ctrl(&pmcdev->di_ctrl, DIM_DI_DEV_NUM);
err_cleanup:
    pci_set_drvdata(pdev, NULL);

    return ret;
}

static void pcie_dim_remove(struct pci_dev *pdev)
{
    struct pcie_dim_t *pmcdev = pci_get_drvdata(pdev);

    if (!pmcdev) {
        dev_warn(&pdev->dev, "No device data found");
        return;
    }
    dev_info(&pdev->dev, "Removing PCIe %s device", DIM_DRV_NAME);

    /* 清理 CAN FD 控制器 */
    exit_xcan_ctrl(&pmcdev->xcanfd_ctrl, DIM_CANFD_DEV_NUM);
    dev_info(pmcdev->dev, "Exit %s controller success", pmcdev->xcanfd_ctrl.name);

    /* 注销 DI 控制器 */
    exit_di_ctrl(&pmcdev->di_ctrl, DIM_DI_DEV_NUM);
    dev_info(pmcdev->dev, "Exit %s controller success", pmcdev->di_ctrl.name);

    /* 注销 PCIe 设备 */
    exit_pcie_dev(pdev, &pmcdev->pcie_dev);
    dev_info(&pdev->dev, "Exit %s device success", pmcdev->pcie_dev.name);

    pci_set_drvdata(pdev, NULL);
    dev_info(&pdev->dev, "Remove PCIe %s device success", DIM_DRV_NAME);
}

/* PCI 设备 ID 表 */
static const struct pci_device_id pcie_dim_ids[] = {
    { PCI_DEVICE(0x594D, 0x0002) },     /* di module */
    { 0, }
};
MODULE_DEVICE_TABLE(pci, pcie_dim_ids);

/* PCI DI 驱动结构 */
struct pci_driver pcie_dim_driver = {
    .name = DIM_DRV_NAME,
    .id_table = pcie_dim_ids,
    .probe = pcie_dim_probe,
    .remove = pcie_dim_remove,
};
